/*
 * 该协议为台铃充电协议
 *
 * 充电互认策略：电池作为主机与充电器进行报文互认（新国标要求）
 * 1、充电器 DC 充电插头接入电池，电池切换成主机，COM 有持续扩展指令报文发送，充电器回复充电互认报文。 （电池接收到 DETC 信号后变成 485 主机与充电器通讯）
 * 2、电池收到充电器的扩展通讯应答报文后，允许持续充电电池通过扩展通讯报文与充电器握手后保持发送基本通讯指令，充电器握手成功后不应答基本通讯指令。
 * 3、无 DETC 信号，电池切换成 485 从机与控制器通讯，在车上 DETC 不能接入；一旦接入 DETC 就进入充电模式优先。；
 * 4、电池与充电器扩展指令握手成功后不在发送扩展指令
 * 5、握手流程：电池主机发送扩展指令=>充电器回应扩展指令=>通讯握手成功，不再发送扩展指令，基本指令 byte7 充电状态发送握手成功、充电器接入状态；
 * 6、数据发送频率间隔 1s；
 * 7、电池判断充满后 byte7 中充满标志置位，长时间静置，SOC 降到 90%以下，清 0 充满标志；一有放电电流清 0 充满标志位。
 */
#include "TaiLingChargeProtocol.h"

#include <stdio.h>

#include "port.h"

#define command_symbol    0XFF        /* 指令符 */
#define temp_offset(data) (data + 50) /* 温度偏移 */

typedef enum {
  battery_nichrome             = 0x00,  // 镍铬
  battery_nickel_metal_hydride = 0x01,  // 镍氢
  battery_plumbic_acid         = 0x02,  // 铅酸
  battery_ternary              = 0x03,  // 三元
  battery_lithium_iron         = 0x04,  // 铁锂
  battery_lithium_manganese    = 0x05,  // 锰锂
} battery_t;

typedef enum {
  /* 查询状态位 */
  frame_status_null     = 0x0000,  // 空
  frame_status_select   = 0x0001,  // 查询
  frame_status_ack      = 0x0002,  // 应答
  frame_status_set      = 0x0003,  // 设定
  frame_status_complete = 0x0004,  // 完成
  frame_status_test     = 0xFFFF,  // 测试用
} frame_status_t;

typedef enum {
  /* 查询命令 */
  frame_cmd_null               = 0x0000,  // 空
  frame_cmd_charge_voltage_min = 0x0001,  // 最低充电电压
  frame_cmd_charge_voltage_max = 0x0002,  // 最高充电电压
  frame_cmd_charge_current_min = 0x0003,  // 最低充电电流
  frame_cmd_charge_current_max = 0x0004,  // 最高充电电流
  frame_cmd_charge_temp_min    = 0x0005,  // 最低充电温度
  frame_cmd_charge_temp_max    = 0x0006,  // 最高充电温度
  frame_cmd_test               = 0xFFFF,  // 测试用
} frame_cmd_t;

#define WORD_16_L_BYTE 0
#define WORD_16_H_BYTE 1

typedef struct {
  uint8 _0 : 1;
  uint8 _1 : 1;
  uint8 _2 : 1;
  uint8 _3 : 1;
  uint8 _4 : 1;
  uint8 _5 : 1;
  uint8 _6 : 1;
  uint8 _7 : 1;
} _8bit;

typedef union {
  uint8 data;
  _8bit bit;
} uint8_bit;

typedef union {
  uint8_bit byte[8];
  uint16    word_16;
  uint32    word_32;
  uint64    word_64;
} typ_iow;

static BOOLEAN handshake_flag = FALSE;  // FALSE为未握手状态

static uint8 CRC8Table[256] = {
    // CRC8 校验 x8 + x2 + x + 1
    0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,  //
    0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,  //
    0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,  //
    0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,  //
    0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,  //
    0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,  //
    0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,  //
    0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,  //
    0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,  //
    0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,  //
    0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,  //
    0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,  //
    0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,  //
    0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,  //
    0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,  //
    0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3   //
};
static uint8 CRC8Calcu(uint8 *p, uint8 Length) {
  uint8 crc8 = 0;
  for (; Length > 0; Length--) {
    crc8 = CRC8Table[crc8 ^ *p];
    p++;
  }
  return (crc8);
}

static BOOLEAN charger_connection_status_get(void) { return FALSE; }
static BOOLEAN charger_status_get(void) { return FALSE; }
static BOOLEAN charger_full_status_get(void) {
  /* 7、电池判断充满后 byte7 中充满标志置位，长时间静置，SOC 降到 90%以下，清 0 充满标志；一有放电电流清 0 充满标志位。 */
  return FALSE;
}

void    TaiLingCharge_Protocol_Init(void) {}
BOOLEAN TaiLingCharge_Protocol_RecvFrame_Process(uint8 *pRecvMsg, uint16 RevLen) {
  if (handshake_flag == FALSE &&                          // 当前未未握手状态
      pRecvMsg[0] == TaiLingCharge_Protocol_FrameHead &&  //
      pRecvMsg[1] == command_symbol &&                    //
      CRC8Calcu(pRecvMsg, RevLen - 1) == pRecvMsg[RevLen - 1]) {
    /* 握手成功 */
    handshake_flag = TRUE;
  }
}
uint16 TaiLingCharge_Protocol_SendFrame_Process(uint8 *SendBuff, uint16 BuffLen) {
  uint16  send_len = 0;
  typ_iow temp;

  if (1 &&                          // 充电器接入
      (handshake_flag == FALSE)) {  // 握手状态为未握手状态
    /* 扩展通讯指令(握手指令组包) */
    SendBuff[send_len++] = TaiLingCharge_Protocol_FrameHead;
    SendBuff[send_len++] = command_symbol;

    temp.word_16         = frame_status_select;
    SendBuff[send_len++] = temp.byte[WORD_16_H_BYTE].data;
    SendBuff[send_len++] = temp.byte[WORD_16_L_BYTE].data;

    temp.word_16         = frame_cmd_null;
    SendBuff[send_len++] = temp.byte[WORD_16_H_BYTE].data;
    SendBuff[send_len++] = temp.byte[WORD_16_L_BYTE].data;

    temp.word_16         = 0X0000;
    SendBuff[send_len++] = temp.byte[WORD_16_H_BYTE].data;
    SendBuff[send_len++] = temp.byte[WORD_16_L_BYTE].data;

    SendBuff[send_len++] = CRC8Calcu(SendBuff, send_len);
  }

  if (handshake_flag) {
    /* 基本通讯指令 */
    m_systempause_start(1000);

    SendBuff[send_len++] = TaiLingCharge_Protocol_FrameHead; /* 起始符 */
    SendBuff[send_len++] = battery_lithium_manganese;        /* 电池种类 */

    temp.word_16         = 5460; /* 电压单位0.01V */
    SendBuff[send_len++] = temp.byte[WORD_16_H_BYTE].data;
    SendBuff[send_len++] = temp.byte[WORD_16_L_BYTE].data;

    temp.word_16         = 400; /* 电流单位0.01 */
    SendBuff[send_len++] = temp.byte[WORD_16_H_BYTE].data;
    SendBuff[send_len++] = temp.byte[WORD_16_L_BYTE].data;

    SendBuff[send_len++] = temp_offset(22); /* 偏移量-50 */

    temp.byte[0].bit._0  = handshake_flag;                   // 握手状态 1表示握手
    temp.byte[0].bit._1  = charger_connection_status_get();  // 充电器连接状态 1表示连接
    temp.byte[0].bit._2  = charger_status_get();             // 充电状态 1表示正在充电
    temp.byte[0].bit._3  = charger_full_status_get();        // 充满状态 1表示充满
    SendBuff[send_len++] = temp.byte[0].data;

    SendBuff[send_len++] = CRC8Calcu(SendBuff, send_len);

    m_systempause_end();
  }

  return send_len;
}